structure tigerescap :> tigerescap =
struct

open tigerabs
open tigertab

type depth = int
type escEnv = (symbol, depth * bool ref) Tabla

(* travVar : escEnv -> depth -> var -> unit *)
fun travVar env d s =
	case s of
	SimpleVar n =>
		(case tabBusca(n, env) of
		SOME (dd, b) => if d>dd then b:=true else ()
		| NONE => raise Fail ("escape?? "^n^" inexist."))
	| FieldVar(v, _) => travVar env d v
	| SubscriptVar(v, e) =>
		(travVar env d v; travExp env d e)

(* travExp : escEnv -> depth -> exp -> unit *)
and travExp env d s =
	case s of
	VarExp(v, _) => travVar env d v
	| CallExp({func, args}, nl) => travExp env d (SeqExp(args, nl))
	| OpExp({left, oper, right}, _) =>
		(travExp env d left; travExp env d right)
	| RecordExp({fields, ...}, nl) => travExp env d (SeqExp(map #2 fields, nl))
	| SeqExp(le, nl) =>
		(foldl (fn (e, (v, d)) => (travExp v d e; (v, d)))
			(env, d) le; ())
	| AssignExp({var, exp}, _) =>
		(travVar env d var; travExp env d exp)
	| IfExp({test, then', else'=NONE}, _) =>
		(travExp env d test; travExp env d then')
	| IfExp({test, then', else'=SOME e}, _) =>
		(travExp env d test; travExp env d then'; travExp env d e)
	| WhileExp({test, body}, _) =>
		(travExp env d test; travExp env d body)
	| ForExp({var, escape, lo, hi, body}, _) =>
		let	val env' = tabRInserta(var, (d, escape), env);
		in	travExp env d lo;
			travExp env d hi;
			travExp env' d body
		end
	| LetExp({decs, body}, _) =>
		travExp (travDecs env d decs) d body
	| ArrayExp({size, init, ...}, _) => 
		(travExp env d size; travExp env d init)
	| _ => ()

(* travDecs : escEnv -> depth -> dec list -> escEnv *)
and travDecs env d decs =
	let
(* travDec recorre una declaración
   travDec : dec * escEnv -> escEnv *)
		fun travDec (FunctionDec l, e) =
			let
(* travFunc recorre una declaración de función simple
   travFunc : ({params : field list, body : exp, ...} * pos) -> unit *)
				fun travFunc ({params, body, ...}, _) = 
					let
(* travParam recorre un parámetro de una declaración de función
   travParam : {name : symbol, escape : bool ref, ...} * escEnv -> escEnv *)
						fun travParam ({name, escape, ...}, ee) = 
							tabRInserta(name, (d+1, escape), ee)
					(* recorre los parámetros de derecha a izquierda *)
						val env' = foldr travParam e params
					in travExp env' (d+1) body end
			in (app travFunc l; e) end
		|	travDec (VarDec ({name, escape, init, ...}, _), e) =
				(travExp e d init; tabRInserta(name, (d, escape), e))
		|	travDec (TypeDec _, e) = e
	in foldl travDec env decs end

(* findEscape : exp -> unit *)
fun findEscape prog = travExp (tabNueva()) 0 prog

end
